package cn.wx.utils;


import cn.wx.io.Resources;
import cn.wx.session.Configuration;
import cn.wx.session.Mapper;
import cn.wx.sqlSession.defaults.DefaultSqlSession;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * 通过dom4j+xpath 解析xml文件
 */
public class XMLConfigBuilder {

    /**
     * 将数据库配置封装到 Configuration 对象中
     * @param sqlSession 存放 Configuration 对象的对象 获取 Mapper 对象
     * @param conf 配置文件流
     */
    public static void loadConfiguration(DefaultSqlSession sqlSession, InputStream conf) {
        // 封装配置文件
        Configuration config = new Configuration();

        SAXReader saxReader = new SAXReader();
        try {
            // 读取XML文件,获得document对象
            Document document = saxReader.read(conf);
            Element root = document.getRootElement(); // 获取根节点
            // 加载数据库配置文件
            Element properties = root.element("properties");
            String dbProperties = properties.attributeValue("resource");
            InputStream in = XMLConfigBuilder.class.getClassLoader().getResourceAsStream(dbProperties);
            Properties prop = new Properties();
            prop.load(in);
            // 获取 property 节点
            List<Element> dataElement = root.selectNodes("//property");
            // 获取的是当前节点的子节点的某名称的所有节点
//            List<Element> dataElement = root.elements("property");
            // 设置数据库连接属性
            for (Element element : dataElement) {
                String name = element.attributeValue("name");
                String value = element.attributeValue("value").replace("${", "").replace("}", "");
                switch(name) {
                    case "driver" -> config.setDriver(prop.getProperty(value));
                    case "url" -> config.setUrl(prop.getProperty(value));
                    case "username" -> config.setUsername(prop.getProperty(value));
                    case "password" -> config.setPassword(prop.getProperty(value));
                }
            }
            // 获取mapper
            List<Element> mapperElements = root.selectNodes("//mappers/mapper");
            Map<String, Mapper> mappers = new HashMap<>();
            for (Element mapperElement : mapperElements) {
                // 获取 resource 属性，判断是否是 xml 文件
                Attribute attribute = mapperElement.attribute("resource");
                mappers.putAll(loadMapperConfiguration(attribute.getValue()));
            }
            config.setMappers(mappers);
            sqlSession.setConfig(config);
            System.out.println(sqlSession);
        } catch (DocumentException | IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 解析 mapper.xml 文件，
     * @param mapperPath mapper文件的名称
     * @return 当前 mapper 文件里面的所有 mapper 对象
     * @throws IOException 关闭流
     */
    public static Map<String, Mapper> loadMapperConfiguration(String mapperPath) throws IOException {
        Map<String, Mapper> mappers = new HashMap<>();
        // 读取XML文件,获得document对象
        try (InputStream in = Resources.getResourceAsStream(mapperPath)) {
            SAXReader saxReader = new SAXReader();
            Document document = null;
            document = saxReader.read(in);
            Element root = document.getRootElement(); // 获取根节点
            String namespace = root.attributeValue("namespace");
            List<Element> selects = root.selectNodes("//select");
            for (Element select : selects) {
                String key = namespace + select.attributeValue("id");
                String sql = select.getText();
                String resultType = select.attributeValue("resultType");
                Mapper mapper = new Mapper();
                mapper.setSql(sql);
                mapper.setResultType(resultType);
                mappers.put(key, mapper);
            }
        } catch (DocumentException e) {
            throw new RuntimeException(e);
        }
        return mappers;
    }
}
